
#pragma once

#include "hash.h"

typedef enum ObjType
{
    OBJ_UNDEFINED   = 0,
    OBJ_NIL         = 1,
    OBJ_T           = 2,
    OBJ_ID          = 3,
    OBJ_LIST        = 4,
    OBJ_INT_NUM     = 5,
    OBJ_DBL_NUM     = 6,
    OBJ_STRING      = 7,
    
    /*
     * this particular type of object considered as atom, it shall not be used in such functions
     * as print, just in list-manipulation only
     */
    OBJ_USERDEFINED = 16,
} ObjType;

#define OBJ_BODY() \
    ObjType      type

typedef struct Obj
{
    OBJ_BODY();
}                   Obj;

/*
 * global nil object. Can be converted to List (nil is the same as the empty list)
 */
extern Obj * g_nil_obj;

/*
 * global t object
 */
extern Obj * g_t_obj;

typedef struct Id
{
    OBJ_BODY();

    StrHash      hash;

    // actually redundant, since we can find corresponding value with `id'
    const char *    str;

    // namespace, this id belongs to
    struct Id *   ns;
}                   Id;


typedef struct List
{
    OBJ_BODY();

    Obj *         car;
    struct List * cdr;
} List;


typedef struct IntNum
{
    OBJ_BODY();

    int             val;
} IntNum;

typedef struct DblNum
{
    OBJ_BODY();

    double          val;
} DblNum;

typedef struct Str
{
    OBJ_BODY();

    char            str[1];
} Str;
